home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-19
/
intrlib1.zip
/
INPUT.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-03-10
|
26KB
|
822 lines
/******************************************************************************
* Iteraction library - input handler. *
* *
* Written by Gershon Elber, Oct. 1990 *
*******************************************************************************
* Supported device: *
* 1. Keyboard. *
* 2. Mouse (MS compatible). *
* 3. Joystick (uses AT class BIOS intrrupt 0x15, ah = 0x84). *
*******************************************************************************
* History: *
* 3 Oct 90 - Version 1.0 by Gershon Elber. *
* 17 Feb 92 - Version 2.0 by Gershon Elber - support for DJGPP. *
******************************************************************************/
#include <stdio.h>
#include <dos.h>
#ifdef __MSDOS__
#include <conio.h>
#include "mousedrv.h"
#endif /* _MSDOS__ */
#ifdef DJGCC
#include <mouse.h>
#endif /* DJGCC */
#include "intr_loc.h"
#include "intr_gr.h"
#define MAX_REGISTERED_KEYS 50 /* Maximum number of registered keys. */
#define JOYSTICK_MAX_MOVE 10 /* Maximum single joystick movement. */
#define JOYSTICK_INC_MOVE 4 /* Increment movement factor. */
#define SHIFT_KEY_MOVES 12
typedef struct {
int KeyStroke;
IntrIntFunc ActionFunc;
} RegisterKeyStruct;
int _IntrActiveDevices = 0;
IntrBType _IntrDetachKbdFromMouse = FALSE;
static int
IntrATKeyboard = FALSE, /* If support AT style keyboard bios. */
NumOfRegisteredKeys = 0,
PushedKbdEvent = -1,
JoystickMinX = 0,
JoystickMaxX = 255,
JoystickMinY = 0,
JoystickMaxY = 255,
JoystickCenterX = 128,
JoystickCenterY = 128,
JoystickTolerance = 16,
MouseSensitivity = 16,
LastInputChar = -1;
static IntrBType
HandleInternalEvents = TRUE,
PropagateInternalEvents = TRUE,
NoJoystick = TRUE;
static RegisterKeyStruct RegisteredKeys[MAX_REGISTERED_KEYS];
static IntrVoidFunc
IntrIdleFunction = NULL;
static void IntrFlushKbd(void);
static int UpdateGetPointKbd(int *Dx, int *Dy);
static int JoystickMove(int *Dx, int *Dy, IntrEventType *Event);
static void JoystickWaitButton0(void);
static void JoystickWaitButton1(void);
/****************************************************************************
* Routine to set the function to execute on idle. *
****************************************************************************/
void IntrSetIdleFunction(IntrVoidFunc IdleFunction)
{
IntrIdleFunction = IdleFunction;
}
/****************************************************************************
* Routine to set an AT bios support for keyboard. *
****************************************************************************/
void IntrSetAtKeyboard(IntrBType IsATKeyboard)
{
IntrATKeyboard = IsATKeyboard;
}
/****************************************************************************
* Routine to draw cursor shape at given location. Shape is specified by *
* CurrentCursor variable. *
****************************************************************************/
void IntrSetMouseSensitivity(int Sensitivity)
{
MouseSensitivity = Sensitivity;
}
/****************************************************************************
* Routine to register a KeyStroke. Returns TRUE if O.K. *
* If stroke is regular ASCII it must be <256. >256 signals it is enhanced. *
****************************************************************************/
IntrBType IntrRegisterKeyStroke(int KeyStroke, IntrIntFunc ActionFunc)
{
if (NumOfRegisteredKeys >= MAX_REGISTERED_KEYS)
return FALSE;
else {
RegisteredKeys[NumOfRegisteredKeys].KeyStroke = KeyStroke;
RegisteredKeys[NumOfRegisteredKeys++].ActionFunc = ActionFunc;
return TRUE;
}
}
/****************************************************************************
* Routine to test if given key is registered. If TRUE the relative *
* registered function ActionFunc is been applied. *
****************************************************************************/
static IntrBType IsRegisteredKey(int KeyStroke)
{
int i;
/* Dont activate any registered function if something is been pop up. */
if (!_IntrAllowInternalEvent()) return FALSE;
for (i = 0; i < NumOfRegisteredKeys; i++)
if (RegisteredKeys[i].KeyStroke == KeyStroke) {
if (RegisteredKeys[i].ActionFunc != NULL)
RegisteredKeys[i].ActionFunc(KeyStroke);
return TRUE;
}
return FALSE;
}
/****************************************************************************
* Routine to get one character from the keyboard. If IntrATKeyboard is set *
* then it is assumed AT style keyboard bios calls are supported. *
****************************************************************************/
int IntrGetch(void)
{
static unsigned int LastKey = 0;
unsigned int Key;
union REGS regs;
#ifdef __MSDOS__
if (IntrATKeyboard) {
if (LastKey) {
/* Last one was extended code, and we returned 0 instead. */
Key = LastKey;
LastKey = 0;
return Key;
}
else {
regs.h.ah = 0x10;
int86(0x16, ®s, ®s);
if (regs.h.al)
return regs.h.al;
else {
LastKey = regs.h.ah;
return 0;
}
}
}
else
return getch();
#endif /* __MSDOS__ */
#ifdef DJGCC
if (LastKey) {
/* Last one was extended code, and we returned 0 instead. */
Key = LastKey;
LastKey = 0;
return Key;
}
else {
Key = getkey();
if (Key & 0xff00) {
LastKey = Key & 0xff;
return 0;
}
else {
return Key;
}
}
#endif /* DJGCC */
}
/****************************************************************************
* Routine to test if character keyboard queue is not empty. *
****************************************************************************/
int IntrKbHit(void)
{
#ifdef DJGCC
union REGS regs;
if (IntrATKeyboard) {
regs.h.ah = 0x11;
int86(0x16, ®s, ®s);
/* If Z flag clear - queue is no empty: */
return (regs.x.flags & 0x40) == 0;
}
else
#endif /* DJGCC */
return kbhit();
}
/****************************************************************************
* Routine to flush keyboard buffer. *
****************************************************************************/
static void IntrFlushKbd(void)
{
while (IntrKbHit())
if (IntrGetch() == 0) IntrGetch();
}
/****************************************************************************
* Routine to update Dx, Dy coordinates According to key pressed. *
* Returns Event (Select, abort, etc.) *
****************************************************************************/
static int UpdateGetPointKbd(int *Dx, int *Dy)
{
int c, Event = INTR_EVNT_MOVE;
*Dx = *Dy = 0;
c = LastInputChar = IntrGetch();
if (c > 0 && (IsRegisteredKey(c) || _IntrDetachKbdFromMouse))
return INTR_EVNT_KEY;
else
switch (c) {
case 0:
c = IntrGetch();
LastInputChar = 256 + c;
if (IsRegisteredKey(c + 256) || _IntrDetachKbdFromMouse)
return INTR_EVNT_KEY;
else
switch (c) {
case 71:
*Dx = -1; /* Arrows - move 1 at a time. */
*Dy = -1;
break;
case 72:
*Dy = -1;
break;
case 73:
*Dx = 1;
*Dy = -1;
break;
case 75:
*Dx = -1;
break;
case 77:
*Dx = 1;
break;
case 79:
*Dx = -1;
*Dy = 1;
break;
case 80:
*Dy = 1;
break;
case 81:
*Dx = 1;
*Dy = 1;
break;
default:
Event = INTR_EVNT_KEY;
break;
}
break;
case 9:
Event = INTR_EVNT_MIDDLE_BUTTON;
break;
case 10:
case 13:
Event = INTR_EVNT_SELECT;
break;
case ' ':
Event = INTR_EVNT_ABORT;
break;
case '1':
*Dx = -SHIFT_KEY_MOVES; /* Shifted arrows. */
*Dy = SHIFT_KEY_MOVES;
break;
case '2':
*Dy = SHIFT_KEY_MOVES;
break;
case '3':
*Dx = SHIFT_KEY_MOVES;
*Dy = SHIFT_KEY_MOVES;
break;
case '4':
*Dx = -SHIFT_KEY_MOVES;
break;
case '6':
*Dx = SHIFT_KEY_MOVES;
break;
case '7':
*Dx = -SHIFT_KEY_MOVES;
*Dy = -SHIFT_KEY_MOVES;
break;
case '8':
*Dy = -SHIFT_KEY_MOVES;
break;
case '9':
*Dx = SHIFT_KEY_MOVES;
*Dy = -SHIFT_KEY_MOVES;
break;
default:
Event = INTR_EVNT_KEY;
break;
}
return Event;
}
/****************************************************************************
* Routine to get joystick movement and/or joystick button press. *
* uses int 0x15 service 0x84 to detect joystick events. *
* Joystick is calibrated using JoystickCalibrate routine that sets the *
* following variables.: *
* 1. JoystickCenterX, JoystickCenterY - center values (joystick rest pos.). *
* 2. JoystickMinX, JoystickMinY - minimum values from joystick. *
* 3. JoystickMaxX, JoystickMaxX - maximum values from joystick. *
* 4. JoystickTolerance - %10 of Max - Min value. *
* Movement is assumed if value read differs from Center by Tolerance. *
* Amount of movement is set so JoystickMaxMove for extremum values. *
****************************************************************************/
static int JoystickMove(int *Dx, int *Dy, IntrEventType *Event)
{
static int JoystickMaxMove = JOYSTICK_MAX_MOVE;
union REGS regs;
*Event = INTR_EVNT_NONE;
*Dx = *Dy = 0;
/* Test if joystick buttons has been pressed. */
regs.h.ah = 0x84;
regs.x.dx = 0x0000;
int86(0x15, ®s, ®s);
if ((regs.h.al & 0x30) == 0)
*Event = INTR_EVNT_MIDDLE_BUTTON;
else if ((regs.h.al & 0x10) == 0)
*Event = INTR_EVNT_SELECT;
else if ((regs.h.al & 0x20) == 0)
*Event = INTR_EVNT_ABORT;
if (*Event != INTR_EVNT_NONE) {
JoystickMaxMove = JOYSTICK_MAX_MOVE; /* Go back to minimum movement. */
return TRUE;
}
/* Test if movement occured: */
regs.h.ah = 0x84;
regs.x.dx = 0x0001;
int86(0x15, ®s, ®s);
if (ABS(((int) regs.x.ax) - JoystickCenterX) > JoystickTolerance)
*Dx = (int) (JoystickMaxMove * (((int) regs.x.ax) - JoystickCenterX) /
((IntrRType) (JoystickMaxX - JoystickMinX)));
if (ABS(((int) regs.x.bx) - JoystickCenterY) > JoystickTolerance)
*Dy = (int) (JoystickMaxMove * (((int) regs.x.bx) - JoystickCenterY) /
((IntrRType) (JoystickMaxY - JoystickMinY)));
if (*Dx != 0 || *Dy != 0) {
*Event = INTR_EVNT_MOVE;
JoystickMaxMove += JOYSTICK_INC_MOVE;
return TRUE;
}
else
JoystickMaxMove = JOYSTICK_MAX_MOVE; /* Go back to minimum movement. */
return FALSE;
}
/****************************************************************************
* Routine to wait until joystick button 0 is pressed. *
* If the button is not pressed for 10 seconds NoJoystick is set to TRUE. *
****************************************************************************/
static void JoystickWaitButton0(void)
{
int i;
union REGS regs;
for (i = 0; i < 1000; i++) {
regs.h.ah = 0x84;
regs.x.dx = 0x0000;
int86(0x15, ®s, ®s);
if ((regs.x.ax & 0x10) == 0) return;
delay(10); /* 10 miliseconds. */
}
NoJoystick = TRUE;
}
/****************************************************************************
* Routine to wait until joystick button 1 is pressed. *
* If the button is not pressed for 10 seconds NoJoystick is set to TRUE. *
****************************************************************************/
static void JoystickWaitButton1(void)
{
int i;
union REGS regs;
for (i = 0; i < 1000; i++) {
regs.h.ah = 0x84;
regs.x.dx = 0x0000;
int86(0x15, ®s, ®s);
if ((regs.x.ax & 0x20) == 0) return;
delay(10); /* 10 miliseconds. */
}
NoJoystick = TRUE;
}
/****************************************************************************
* Routine to initialize the joystick. *
****************************************************************************/
static void JoystickInit(void)
{
union REGS regs;
IntrCursorShapeStruct Cursor;
Cursor.CursorType = INTR_CURSOR_ARROW;
NoJoystick = FALSE;
IntrQueryContinue2("Move Joystick to top left and press Button 0",
JoystickWaitButton0,
INTR_COLOR_RED,
INTR_COLOR_BLUE,
INTR_COLOR_YELLOW,
8,
&Cursor,
0);
if (NoJoystick) {
_IntrActiveDevices &= ~INTR_INPT_DEVICE_JOYSTICK;
IntrQueryContinue("No joystick detected.",
INTR_COLOR_RED,
INTR_COLOR_BLUE,
INTR_COLOR_YELLOW,
INTR_COLOR_MAGENTA,
8,
&Cursor,
0);
return;
}
regs.h.ah = 0x84;
regs.x.dx = 0x0001;
int86(0x15, ®s, ®s);
JoystickMinX = regs.x.ax;
JoystickMinY = regs.x.bx;
IntrQueryContinue2("Move Joystick to bottom right and press Button 1",
JoystickWaitButton1,
INTR_COLOR_RED,
INTR_COLOR_BLUE,
INTR_COLOR_YELLOW,
8,
&Cursor,
0);
if (NoJoystick) {
_IntrActiveDevices &= ~INTR_INPT_DEVICE_JOYSTICK;
IntrQueryContinue("No joystick detected.",
INTR_COLOR_RED,
INTR_COLOR_BLUE,
INTR_COLOR_YELLOW,
INTR_COLOR_MAGENTA,
8,
&Cursor,
0);
return;
}
regs.h.ah = 0x84;
regs.x.dx = 0x0001;
int86(0x15, ®s, ®s);
JoystickMaxX = regs.x.ax;
JoystickMaxY = regs.x.bx;
IntrQueryContinue2("Move Joystick to center and press Button 0",
JoystickWaitButton0,
INTR_COLOR_RED,
INTR_COLOR_BLUE,
INTR_COLOR_YELLOW,
8,
&Cursor,
0);
if (NoJoystick) {
_IntrActiveDevices &= ~INTR_INPT_DEVICE_JOYSTICK;
IntrQueryContinue("No joystick detected.",
INTR_COLOR_RED,
INTR_COLOR_BLUE,
INTR_COLOR_YELLOW,
INTR_COLOR_MAGENTA,
8,
&Cursor,
0);
return;
}
regs.h.ah = 0x84;
regs.x.dx = 0x0001;
int86(0x15, ®s, ®s);
JoystickCenterX = regs.x.ax;
JoystickCenterY = regs.x.bx;
/* Make sure domain is not empty (prevent divide by zero). */
if (JoystickMinX == JoystickMaxX) JoystickMaxX++;
if (JoystickMinY == JoystickMaxY) JoystickMaxY++;
}
/****************************************************************************
* Routine to select devices to handle (see IntrInputDeviceType). *
****************************************************************************/
void IntrSetInputDevice(int Devices)
{
int OldDevices = _IntrActiveDevices;
_IntrActiveDevices = Devices;
#ifdef __MSDOS__
if (OldDevices & INTR_INPT_DEVICE_MOUSE &&
!(_IntrActiveDevices & INTR_INPT_DEVICE_MOUSE)) {
/* Close the mouse interaction. */
MouseClose();
}
else if (!(OldDevices & INTR_INPT_DEVICE_MOUSE) &&
_IntrActiveDevices & INTR_INPT_DEVICE_MOUSE) {
/* Open a mouse interaction. */
MouseInit(MouseSensitivity);
}
#endif /* __MSDOS__ */
#ifdef DJGCC
/* Make sure the mouse is initialized by invoking MouseGetEvent once */
/* and then initialize the mouse sensitivity as desired. */
{
MouseEvent MEvent;
MouseGetEvent(M_POLL | M_NOPAINT, &MEvent);
MouseSetSpeed(MouseSensitivity);
}
#endif /* DJGCC */
if (!(OldDevices & INTR_INPT_DEVICE_JOYSTICK) &&
_IntrActiveDevices & INTR_INPT_DEVICE_JOYSTICK) {
/* Set up the joystick. */
JoystickInit();
}
}
/****************************************************************************
* Routine to set Handling of internal events. *
****************************************************************************/
void IntrSetHandleInternalEvents(IntrBType HandleEvents,
IntrBType PropagateEvents)
{
HandleInternalEvents = HandleEvents;
PropagateInternalEvents = PropagateEvents;
}
/****************************************************************************
* Same as IntrGetEventWait but waits for Abort or Select. *
****************************************************************************/
IntrEventType IntrGetEventWaitSA(int *x, int *y)
{
IntrEventType Event;
while ((Event = IntrGetEventWait(x, y)) != INTR_EVNT_SELECT &&
Event != INTR_EVNT_ABORT &&
Event != INTR_EVNT_MIDDLE_BUTTON);
return Event;
}
/****************************************************************************
* Routine to flush all input events. *
****************************************************************************/
void IntrInputFlush(void)
{
#ifdef __MSDOS__
if (_IntrActiveDevices & INTR_INPT_DEVICE_MOUSE)
MouseFlushBuffer();
#endif /* __MSDOS__ */
if (_IntrActiveDevices & INTR_INPT_DEVICE_KEYBOARD)
IntrFlushKbd();
}
/****************************************************************************
* Routine to get one event - move in x, y, select, abort etc. *
* Note this routine returns x, y in screen coordinates. *
* This routine waits until event occurs. *
****************************************************************************/
IntrEventType IntrGetEventWait(int *x, int *y)
{
IntrEventType Event;
int OrigX = GRCurrentCursorX,
OrigY = GRCurrentCursorY;
/* Read events while the events are internal. */
do {
if (IntrIdleFunction != NULL)
(IntrIdleFunction)(); /* Do something useful if idle. */
IntrShowCursor(GRCurrentCursorX, /* Draw cursor - starting position. */
GRCurrentCursorY);
while ((Event = IntrGetEventNoWait(x, y)) == INTR_EVNT_NONE);
if (Event == INTR_EVNT_MOVE) {
GRCurrentCursorX = OrigX = *x;
GRCurrentCursorY = OrigY = *y;
}
else {
GRCurrentCursorX = OrigX;
GRCurrentCursorY = OrigY;
}
IntrUnShowCursor(); /* Erase last old cursor before quiting. */
}
while (HandleInternalEvents &&
_IntrIsInternalEvent(Event, GRCurrentCursorX, GRCurrentCursorY) &&
!PropagateInternalEvents);
#ifndef DJGCC
/* Clear any pending events. */
if (_IntrActiveDevices & INTR_INPT_DEVICE_MOUSE &&
(Event == INTR_EVNT_ABORT ||
Event == INTR_EVNT_MIDDLE_BUTTON ||
Event == INTR_EVNT_SELECT)) {
delay(250);
IntrInputFlush();
}
#endif /* DJGCC */
return Event;
}
#ifdef DJGCC
/****************************************************************************
* Emulate functions below using the mouse functions provided in DJGCC. *
****************************************************************************/
static MouseEvent MEvent;
static IntrBType MouseQueryBuffer(void)
{
MouseGetEvent(M_POLL | M_NOPAINT | M_MOTION | M_BUTTON_DOWN, &MEvent);
if (MEvent.flags & M_KEYPRESS)
return (MEvent.flags & M_BUTTON_DOWN) ||
((MEvent.flags & M_MOTION) &&
(MEvent.x != GRCurrentCursorX || MEvent.y != GRCurrentCursorY));
}
static void MouseGetBuffer(int *x, int *y, int *Buttons)
{
*x = MEvent.x;
*y = MEvent.y;
if (MEvent.buttons & M_MIDDLE)
*Buttons = 0x03;
else
*Buttons = MEvent.buttons;
}
#endif /* DJGCC */
/****************************************************************************
* Routine to get one event - move in x, y, select, abort etc. *
* Note this routine returns x, y in screen coordinates. *
* This routine does not wait if no event is waiting and no cursor is drawn. *
****************************************************************************/
IntrEventType IntrGetEventNoWait(int *x, int *y)
{
IntrEventType
Event = INTR_EVNT_NONE;
int Buttons, Dx, Dy,
XScreen = GRCurrentCursorX,
YScreen = GRCurrentCursorY;
if (PushedKbdEvent >= 0) {
*x = PushedKbdEvent;
PushedKbdEvent = -1;
return INTR_EVNT_KEY;
}
/* Scan for input from one of the input devices. */
if (_IntrActiveDevices & INTR_INPT_DEVICE_KEYBOARD && IntrKbHit()) {
Event = UpdateGetPointKbd(&Dx, &Dy);
XScreen += Dx;
YScreen += Dy;
}
else if (_IntrActiveDevices & INTR_INPT_DEVICE_MOUSE &&
MouseQueryBuffer()) {
MouseGetBuffer(&XScreen, &YScreen, &Buttons);
if (Buttons == 0x03)
Event = INTR_EVNT_MIDDLE_BUTTON;
else if (Buttons == 0x01)
Event = INTR_EVNT_SELECT;
else if (Buttons == 0x02)
Event = INTR_EVNT_ABORT;
}
else if (_IntrActiveDevices & INTR_INPT_DEVICE_JOYSTICK &&
JoystickMove(&Dx, &Dy, &Event)) {
XScreen += Dx;
YScreen += Dy;
}
if (XScreen < 0) XScreen = 0;
if (YScreen < 0) YScreen = 0;
if (XScreen > GRScreenMaxX) XScreen = GRScreenMaxX;
if (YScreen > GRScreenMaxY) YScreen = GRScreenMaxY;
if ((GRCurrentCursorX != XScreen || GRCurrentCursorY != YScreen) &&
Event == INTR_EVNT_NONE)
Event = INTR_EVNT_MOVE;
switch (Event) {
case INTR_EVNT_KEY:
*x = LastInputChar;
break;
default:
*x = XScreen;
*y = YScreen;
break;
}
return Event;
}
/****************************************************************************
* Routine to get one event - select, abort etc. *
****************************************************************************/
IntrEventType IntrGetTextEventWait(void)
{
IntrEventType
Event = INTR_EVNT_NONE;
while ((Event = IntrGetTextEventNoWait()) == INTR_EVNT_NONE)
if (IntrIdleFunction != NULL)
(IntrIdleFunction)(); /* Do something useful if idle. */
return Event;
}
/****************************************************************************
* Routine to get one event - select, abort etc. *
* This routine does not wait if no event is waiting and no cursor is drawn. *
****************************************************************************/
IntrEventType IntrGetTextEventNoWait(void)
{
int Buttons,
Xtemp = 0,
Ytemp = 0;
IntrEventType
Event = INTR_EVNT_NONE;
/* Wait for input from one of the devices: Mouse/Keyboard. */
if (_IntrActiveDevices & INTR_INPT_DEVICE_MOUSE &&
MouseQueryBuffer()) {
MouseGetBuffer(&Xtemp, &Ytemp, &Buttons);
if (Buttons == 0x03)
Event = INTR_EVNT_MIDDLE_BUTTON;
else if (Buttons == 0x01)
Event = INTR_EVNT_SELECT;
else if (Buttons == 0x02)
Event = INTR_EVNT_ABORT;
if (Event == INTR_EVNT_MOVE) Event = INTR_EVNT_NONE;
}
else if (IntrKbHit()) {
switch (IntrGetch()) {
case 10:
case 13:
Event = INTR_EVNT_SELECT;
break;
case ' ':
Event = INTR_EVNT_ABORT;
break;
}
}
else if (_IntrActiveDevices & INTR_INPT_DEVICE_JOYSTICK)
JoystickMove(&Xtemp, &Ytemp, &Event);
return Event;
}
/****************************************************************************
* One level stack ability to push keyboard event on the stack. *
****************************************************************************/
void IntrPushKbdEvent(int KbdEvent)
{
PushedKbdEvent = KbdEvent;
}
/****************************************************************************
* Maps a screen (x, y) location into a window. Return TRUE if in window. *
****************************************************************************/
IntrBType IntrMapEventToWindow(int WindowID, int x, int y, int *Wx, int *Wy)
{
_IntrWindowStruct
*Window = _IntrFindWndwUsingID(WindowID);
if (_IntrWndwGetWndwInPos(x, y) != Window) return FALSE;
*Wx = x - Window -> BBox.Xmin;
*Wy = y - Window -> BBox.Ymin;
return TRUE;
}
/****************************************************************************
* Maps a screen (x, y) location into a window. Return TRUE if in window. *
****************************************************************************/
IntrBType IntrMapEventToRWindow(int WindowID, int x, int y,
IntrRType *Wx, IntrRType *Wy)
{
int ix, iy;
_IntrWindowStruct
*Window = _IntrFindWndwUsingID(WindowID);
if (!IntrMapEventToWindow(WindowID, x, y, &ix, &iy))
return FALSE;
*Wx = ix * Window -> FBBox._FDx / Window -> BBox._Dx +
Window -> FBBox.FXmin;
*Wy = iy * Window -> FBBox._FDy / Window -> BBox._Dy +
Window -> FBBox.FYmin;
return TRUE;
}